
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unordered_map>
#include <string>
#include <fcntl.h>
#include <sys/stat.h>
#include <vector>
#include <map>
/**
 * 该文件为进程池的公共代码段
 * 进程池为利用命名管道实现的，简称命名管道进程池
 * 代码的主要功能包括：创建进程，控制进程实现委派给它的任务，等待进程
 */
#define SIZE 1024
typedef void(*task_t)(void);

//任务集
void printLog()
{
    std::cout<<"PID:"<<getpid()<<",正在打印日志..."<<std::endl;
}

void MySQLInsert()
{
    std::cout<<"PID"<<getpid()<<",正在将数据插入数据库..."<<std::endl;
}

void NetRequest()
{
    std::cout<<"PID"<<getpid()<<",正在请求网络..."<<std::endl;
}



class Task{
private:
    std::unordered_map<std::string,task_t> st_;
public:
    Task()
    {
        st_ = {{"打印日志",printLog},{"插入数据",MySQLInsert},{"请求网络",NetRequest}};
    }
    void showTask()/*展示任务*/
    {
        std::cout<<"可选任务："<<std::endl;
        std::cout<<" {";
        for(auto&s:st_)
        {
            std::cout<<s.first<<' ';
        }
        std::cout<<'}'<<std::endl;
    }
    void curTask(const std::string& t)/*执行任务*/
    {
        if(st_.find(t) == st_.end())
        {
            std::cout<<"没有这个任务哦~"<<std::endl;
        }
        else
        {
            st_[t]();/*调用任务*/
        }
    }
};

class SubProcesses{
private:
    pid_t id_;
    int processNum_;
    int wfd_;
    std::string name_;
    static int cnt_;
public:
    SubProcesses(pid_t id,int wfd)
    :id_(id),processNum_(cnt_++),wfd_(wfd)
    {
        char buff[SIZE]{0};
        snprintf(buff,SIZE,"Process %d | pid:wfd [%d:%d]",processNum_,id_,wfd_);
        name_ = buff;
    }
    pid_t getId()
    {
        return id_;
    }
    std::string getName()
    {
        return name_;
    }
    int getWfd()
    {
        return wfd_;
    }
};
int SubProcesses::cnt_ = 1;

class ProcessCtrl{
private:
    std::vector<SubProcesses> subProcess_;/*子进程信息表*/
    std::vector<std::string> namePipe_;/*命名管道信息表*/
    int subProcessNum_ ;/*需要创建的子进程数目*/
    mode_t mode_ ;
public:
    ProcessCtrl(int subProcessNum = 3,mode_t mode = 0666)
    :subProcessNum_(subProcessNum),mode_(mode)
    {createProcess();/*开始创建子进程*/}
    void createProcess()
    {
        std::vector<int> vfd;/*关闭子进程的写端*/
        for(int i = 1;i<=subProcessNum_;++i)
        {
            std::string fifoName = "fifo-"+std::to_string(i); 
            int ret = mkfifo(fifoName.c_str(),mode_);/*创建命名管道*/
            if(ret == -1)
            {
                perror("mkfifo");
                exit(1);
            }
            namePipe_.push_back(fifoName);/*存入命名管道*/
            pid_t id = fork();/*创建子进程*/
            if(id < 0)
            {
                perror("fork");
                exit(1);
            }
            else if(id == 0)
            {
                //子进程
                for(auto&fd:vfd)
                {
                    close(fd);
                }
                int rfd = open(fifoName.c_str(),O_RDONLY);
                if(rfd == -1)
                {
                    perror("open");
                    exit(1);
                }
                //开始等待父进程的指令
                waitTask(rfd); /*子进程等待任务委派*/
                close(rfd);
                exit(0);
            }
            //父进程
            int wfd = open(fifoName.c_str(),O_WRONLY);
            if(wfd == -1)
            {
                perror("open");
                exit(1);
            }
            subProcess_.push_back({id,wfd});/*存入子进程信息*/
            fifoName.push_back(wfd);
        }
        
       
    }
    void waitTask(int rfd)/*子进程等待任务委派*/
    {
        while(true)
        {
            char buff[SIZE];
            int n = read(rfd,buff,SIZE);
            if(n == -1)
            {
                perror("read");
                exit(1);
            }
            else if(n>0)
            {
                Task().curTask((std::string)buff);
            }
            else if(n == 0)
            {
                /*证明写端没有写消息了*/
                std::cout<<"写端已经关闭，读端也即将关闭！"<<std::endl;
                break;
            }
        }
        
    }
    /*展示可选进程*/
    void showProcess()
    {
        std::cout<<"目前可用进程有："<<std::endl;
        int i = 0;
        std::cout<<"|";
        for(auto&x:subProcess_)
        {
            std::cout<<"进程编号："<<(i++)<<"进程PID:"<<x.getId()<<"| ";
        }
    }
    /*下达任务给子进程*/
    void sendTask()
    {
        std::cout<<"------------------------"<<std::endl;
        while(true)
        {
            int input = 0;
            do
            {
                showProcess();
                std::cout<<"请选择子进程#";
                std::cin>>input;   
            }while(input<0||input>=subProcessNum_);
            Task().showTask();
            std::string taskName;
            std::cout<<"请选择任务#";
            std::cin>>taskName;
            if(taskName == "exit")
            {
                break;
            }
            std::cout<<"选择进程-> "<<subProcess_[input].getName()<<" 执行"<<taskName<<" 任务"<<std::endl;
            write(subProcess_[input].getWfd(),taskName.c_str(),taskName.size());
            sleep(1);
        }
    }
    /*关闭写端、删除文件、等待子进程退出*/
    void waitProcess()
    {
        for(int i = 0;i<subProcessNum_;++i)
        {
            close(subProcess_[i].getWfd());
            unlink(namePipe_[i].c_str());
            waitpid(subProcess_[i].getId(),nullptr,0);
        }
        std::cout<<"所有子进程已回收！"<<std::endl;
    }
};


int main()
{
    ProcessCtrl pp;
    pp.sendTask();
    return 0;
}